////////////////////////////////////////////////////////////////////////////////
//   Copyright GRGBanking Platform 2011 
//   All rights reserved. 
////////////////////////////////////////////////////////////////////////////////
package components.custom
{

	/*========================================================*/
	/*   Import                                               */
	/*========================================================*/

	import flash.events.Event;
	
	import mx.collections.ArrayCollection;
	import mx.collections.IList;
	import mx.core.ClassFactory;
	import mx.core.IVisualElement;
	import mx.core.mx_internal;
	import mx.events.CollectionEvent;
	import mx.events.CollectionEventKind;
	
	import spark.components.DataGroup;
	import spark.components.IItemRenderer;
	import spark.layouts.TileLayout;
	import spark.layouts.VerticalLayout;
	import spark.utils.LabelUtil;
	
	import components.base.BaseCheckBox;

	/*========================================================*/
	/*   Namespace Use                                        */
	/*========================================================*/

	use namespace mx_internal;

	[Event(name="selectedAllItemCancel", type="flash.events.Event")]
	[Event(name="allItemSelected", type="flash.events.Event")]
	
	public class CheckBoxTileList extends DataGroup
	{

		/*========================================================*/
		/*   Constructor                                          */
		/*========================================================*/

		/**
		 * Constructor
		 */
		public function CheckBoxTileList()
		{
			super();
			var ly:TileLayout = new TileLayout();
			ly.columnAlign = "left";
			ly.orientation = "rows";
			//layout.columnWidth=60;
			//layout.requestedColumnCount=6;
			ly.rowAlign = "justify";
			layout = ly;
			
			itemRenderer = new ClassFactory(BaseCheckBox);

			selectedItems = new ArrayCollection();

			disSelectedItems = new ArrayCollection();
		}

		/*========================================================*/
		/*   Property                                             */
		/*========================================================*/

		private var _disSelectedItems:ArrayCollection;

		private var _labelField:String;

		private var _labelFunction:Function;

		private var _selectedField:String = "selected";

		//-----------------------------------------------------------------------------------------
		// Variables
		//-----------------------------------------------------------------------------------------

		private var _selectedItems:ArrayCollection;

		private var labelFieldOrFunctionChanged:Boolean = false;

		/*========================================================*/
		/*   Function                                             */
		/*========================================================*/

		public function get disSelectedItems():ArrayCollection
		{
			return _disSelectedItems;
		}

		public function set disSelectedItems(value:ArrayCollection):void
		{
			if (_disSelectedItems === value)
				return;

			if (_disSelectedItems)
			{
				_disSelectedItems.removeEventListener(CollectionEvent.COLLECTION_CHANGE,
													  selectedItems_collectionChangeHandler);
			}

			_disSelectedItems = value;

			if (_disSelectedItems)
			{
				_disSelectedItems.addEventListener(CollectionEvent.COLLECTION_CHANGE,
												   selectedItems_collectionChangeHandler, false, 0, true);
			}
		}

		//-----------------------------------------------------------------------------------------
		// DataGroup Overrides
		//-----------------------------------------------------------------------------------------

		/**
		 *  Given a data item, return the correct text a renderer
		 *  should display while taking the <code>labelField</code>
		 *  and <code>labelFunction</code> properties into account.
		 */
		override public function itemToLabel(item:Object):String
		{
			return LabelUtil.itemToLabel(item, labelField, labelFunction);
		}

		/**
		 *  The name of the field in the data provider items to display
		 *  as the label.
		 *  The <code>labelFunction</code> property overrides this property.
		 */
		public function get labelField():String
		{
			return _labelField;
		}

		public function set labelField(value:String):void
		{
			if (_labelField == value)
				return;

			_labelField = value;
			labelFieldOrFunctionChanged = true;
			invalidateProperties();
		}

		/**
		 *  A user-supplied function to run on each item to determine its label.
		 *  The <code>labelFunction</code> property overrides
		 *  the <code>labelField</code> property.
		 *
		 *  <p>You can supply a <code>labelFunction</code> that finds the
		 *  appropriate fields and returns a displayable string. The
		 *  <code>labelFunction</code> is also good for handling formatting and
		 *  localization. </p>
		 *
		 *  <p>The label function takes a single argument which is the item in
		 *  the data provider and returns a String.</p>
		 *  <pre>
		 *  myLabelFunction(item:Object):String</pre>
		 */
		public function get labelFunction():Function
		{
			return _labelFunction;
		}

		public function set labelFunction(value:Function):void
		{
			if (_labelFunction === value)
				return;

			_labelFunction = value;
			labelFieldOrFunctionChanged = true;
			invalidateProperties();
		}

		public function get selectedField():String
		{
			return _selectedField;
		}

		public function set selectedField(value:String):void
		{
			_selectedField = value;
		}

		//-----------------------------------------------------------------------------------------
		// Properties
		//-----------------------------------------------------------------------------------------

		/**
		 * Specifies the objects from the dataProvider which are selected.
		 *
		 * Those items which are selected will appear as checked.
		 */
		[Bindable]
		public function get selectedItems():ArrayCollection
		{
			return _selectedItems;
		}

		public function set selectedItems(value:ArrayCollection):void
		{
			if (_selectedItems === value)
				return;

			if (_selectedItems)
			{
				_selectedItems.removeEventListener(CollectionEvent.COLLECTION_CHANGE,
												   selectedItems_collectionChangeHandler);
			}

			_selectedItems = value;

			if (_selectedItems)
			{
				_selectedItems.addEventListener(CollectionEvent.COLLECTION_CHANGE,
												selectedItems_collectionChangeHandler, false, 0, true);
			}
		}

		/**
		 *  @private
		 */
		override public function updateRenderer(_renderer:IVisualElement, itemIndex:int, data:Object):void
		{
			var renderer:IItemRenderer = IItemRenderer(_renderer);
			renderer.removeEventListener(Event.CHANGE, renderer_changeHandler);
			renderer.addEventListener(Event.CHANGE, renderer_changeHandler, false, 0, true);
			renderer.owner = this;
			renderer.selected = selectedItems.getItemIndex(data) != -1;
			renderer.label = itemToLabel(data);
			renderer.data = data;
			if (data.hasOwnProperty(selectedField))
			{
				renderer.selected = data[selectedField];
				if (data[selectedField] && !selectedItems.contains(data))
				{
					selectedItems.addItem(data);
					
				}
			}
		}

		//-----------------------------------------------------------------------------------------
		// UIComponent Overrides
		//-----------------------------------------------------------------------------------------

		/**
		 *  @private
		 */
		override protected function commitProperties():void
		{
			super.commitProperties();

			if (labelFieldOrFunctionChanged)
			{
				var n:int = numElements;
				for (var i:int = 0; i < n; i++)
				{
					updateRendererLabelProperty(i);
				}
				labelFieldOrFunctionChanged = false;
			}
		}

		/**
		 *  @private
		 */
		override protected function createChildren():void
		{
			if (!layout)
			{
				var layout:VerticalLayout = new VerticalLayout();
				layout.gap = 0;
				this.layout = layout;
			}

			super.createChildren();
		}
		
		override public function set dataProvider(value:IList):void
		{
			selectedItems = new ArrayCollection();
			disSelectedItems = new ArrayCollection();
			super.dataProvider = value;
		}

		/**
		 *  @private
		 */
		mx_internal override function dataProvider_collectionChangeHandler(event:CollectionEvent):void
		{
			// Remove those items from selectedItems which are removed from the dataProvider.
			var i:int, n:int, m:int, index:int, index1:int;
			selectedItems.disableAutoUpdate();
			switch (event.kind)
			{
				case CollectionEventKind.REMOVE:
					n = event.items.length;
					for (i = 0; i < n; i++)
					{
						index = selectedItems.getItemIndex(event.items[i]);
						index1 = disSelectedItems.getItemIndex(event.items[i]);
						if (index >= 0)
						{
							selectedItems.removeItemAt(index);
						}
						if (index1 < 0)
						{
							disSelectedItems.addItem(event.items[i]);
						}
					}
					break;
				case CollectionEventKind.REFRESH:
				case CollectionEventKind.RESET:
					n = selectedItems.length;
					m = disSelectedItems.length;
					for (i = n - 1; i >= 0; i--)
					{
						index = dataProvider.getItemIndex(selectedItems.getItemAt(i));
						if (index >= 0)
						{
							selectedItems.removeItemAt(i);
						}
					}
					for (i = m - 1; i >= 0; i--)
					{
						index1 = dataProvider.getItemIndex(disSelectedItems.getItemAt(i));
						if (index1 < 0)
						{
							disSelectedItems.addItem(dataProvider.getItemAt(i));
						}
					}
					break;
			}
			selectedItems.enableAutoUpdate();

			super.dataProvider_collectionChangeHandler(event);
		}

		//-----------------------------------------------------------------------------------------
		// Event Listeners
		//-----------------------------------------------------------------------------------------

		private function renderer_changeHandler(event:Event):void
		{
			var renderer:IItemRenderer = IItemRenderer(event.target);
			var data:Object = renderer.data;
			var index:int = selectedItems.getItemIndex(data);
			var index1:int = disSelectedItems.getItemIndex(data);
			if (renderer.selected && index < 0)
			{
				selectedItems.addItem(data);
				if(data.hasOwnProperty(_selectedField))
					data[_selectedField] = true;
			}
			if (!renderer.selected && index >= 0)
			{
				selectedItems.removeItemAt(index);
				if(data.hasOwnProperty(_selectedField))
					data[_selectedField] = false;
			}
			if (renderer.selected && index1 >= 0)
			{
				disSelectedItems.removeItemAt(index1);
				if(data.hasOwnProperty(_selectedField))
					data[_selectedField] = true;
			}
			if (!renderer.selected && index1 < 0)
			{
				disSelectedItems.addItem(data);
				if(data.hasOwnProperty(_selectedField))
					data[_selectedField] = false;
			}
			checkAllItemsStatus();
		}
		
		private function checkAllItemsStatus():void
		{
			for(var i:int = 0;i < dataProvider.length;i++){
				var obj:Object = dataProvider.getItemAt(i);
				if(!obj.hasOwnProperty(_selectedField) || !obj[_selectedField]){
					dispatchEvent(new Event("selectedAllItemCancel"));
					return;
				}
			}
			dispatchEvent(new Event("allItemSelected"));
		}

		private function selectedItems_collectionChangeHandler(event:CollectionEvent):void
		{
			var n:uint, i:uint, renderer:IItemRenderer;
			switch (event.kind)
			{
				case CollectionEventKind.ADD:
				case CollectionEventKind.REMOVE:
					n = event.items.length;
					for (i = 0; i < n; i++)
					{
						renderer = getElementAt(dataProvider.getItemIndex(event.items[i])) as IItemRenderer;
						if (renderer)
						{
							renderer.selected = selectedItems.getItemIndex(renderer.data) != -1;
						}
					}
					break;
				case CollectionEventKind.REFRESH:
				case CollectionEventKind.RESET:
					n = numElements;
					for (i = 0; i < n; i++)
					{
						renderer = getElementAt(i) as IItemRenderer;
						if (renderer)
						{
							renderer.selected = selectedItems.getItemIndex(renderer.data) != -1;
						}
					}
					break;
				default:
					return;
			}
			invalidateDisplayList();
		}

		//-----------------------------------------------------------------------------------------
		// Methods
		//-----------------------------------------------------------------------------------------

		private function updateRendererLabelProperty(itemIndex:int):void
		{
			var renderer:IItemRenderer = IItemRenderer(getElementAt(itemIndex));
			if (renderer)
			{
				renderer.label = itemToLabel(renderer.data);
			}
		}
	}
}